home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 001a / b50menu.zip / B50MENU.C next >
C/C++ Source or Header  |  1991-08-08  |  9KB  |  272 lines

  1. //    B50MENU.C:  <ALT> HOT-KEY MENU FOR BOYAN VERSION 5.0
  2. //    
  3. //    Written in Microsoft C 6.00a
  4. //    
  5. //    This program will load and execute BOYAN.COM, and it must be located
  6. //    in the same directory.  (All command line arguments are passed.)  A
  7. //    Keyboard BIOS request interrupt handler is installed that pops-up a
  8. //    help menu when the <Alt> key is pressed at the main terminal screen.
  9.  
  10. char banner[] =
  11. "B50BENU Version 1.0 Copyright 1991 John Navas II, All Rights Reserved\n\n";
  12.  
  13. #include <ctype.h>
  14. #include <dos.h>
  15. #include <fcntl.h>
  16. #include <io.h>
  17. #include <process.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21.  
  22. #define VIDBIOS        (0x10)                // Video BIOS interrupt
  23. #define GETSHADBUF    (0xFE)                // Get Video Shadow Buffer service
  24. #define KEYBIOS        (0x16)                // Keyboard BIOS interrupt
  25. #define KEYREAD        (0)                    // Read Key service
  26. #define KEYSTATUS    (1)                    // Keyboard buffer status service
  27. #define MONOMODE    (7)                    // Monochrome adapter video mode
  28. #define MONOBUF        (0xB000)            // Monochrome video buffer segment
  29. #define COLORBUF    (0xB800)            // Color video buffer segment
  30.  
  31. // These are the two possible values for Boyan's Stack Pointer when B50MENU
  32. // traps a Keyboard BIOS interrupt from Boyan's main terminal screen.  (The
  33. // stack pointer is different on other screens.)
  34. #define B50SP1        (0xFFCA)
  35. #define B50SP2        (0xFFD9)
  36.  
  37. typedef enum { FALSE = 0, TRUE = 1 } BOOL;
  38. typedef unsigned char    BYTE;
  39. typedef unsigned short    WORD;
  40.  
  41. #pragma pack(1)
  42. // layout of character and attribute in the video buffer
  43. typedef union { WORD ca; struct { BYTE ch, at; }; } CHAT;
  44. typedef struct { CHAT chat[80]; } VIDLINE;    // video buffer display line
  45. #pragma pack()
  46. _segment VidSeg = 0;                    // segment for video display buffer
  47. VIDLINE VidSave;                        // save Boyan's status line here
  48. VIDLINE VidMenu;                        // build pop-up menu here
  49. BOOL MenuOn = FALSE;                    // has menu been popped up?
  50.  
  51. // BIOS DATA AREA:
  52. #define KEYBDCNTL()        (*(const volatile WORD far*)0x400017)    // Key states
  53. #define ALTPRESSED()    ((8 & KEYBDCNTL()) != 0)    // <Alt> key pressed
  54. #define VIDEOMODE()        (*(const BYTE far*)0x400049)    // BIOS video mode
  55. #define VIDEOROWS()        (*(const BYTE far*)0x400084)    // screen rows - 1
  56.  
  57. static char boyancnf[] = "BOYAN.CNF";    // name of Boyan's CoNFiguration file
  58. #define NORMOFFSET    (4)                    // offset to Help normal color
  59. BYTE normclr = 0x07;                    // help normal color default
  60. #define HIGHOFFSET    (0x322)                // offset to Help highlight color
  61. BYTE highclr = 0x0F;                    // help highlight color default
  62. static char b50menucnf[] = "B50MENU.CNF";    // name of my CoNFig file
  63. static char boyancom[] = "BOYAN.COM";    // name of Boyan executable
  64. char path[_MAX_PATH];                    // build file path names here
  65. char menu[] =                            // default pop-up menu text
  66. "Act Bep Cfg Dial Echo File Hang Jmp Mac Log New Par Que Run Sav Trn Vu Wp eX Zap";
  67.  
  68. typedef void (_interrupt _far INTHAND)(void);    // interrupt service routine
  69. INTHAND _far *OldKeyReq = 0;            // save old key request int here
  70.  
  71. // BUILD MENU VIDEO LINE FROM TEXT AND ATTRIBUTES:
  72. #pragma check_stack(off)
  73. void
  74. SetupMenu(void)
  75. {
  76.     register int i;
  77.  
  78.     for (i = 0; i < sizeof(menu); ++i) {    // entire line
  79.         VidMenu.chat[i].ch = menu[i];    // text character
  80.         VidMenu.chat[i].at =            // attribute depends on case
  81.             (BYTE)(isupper(menu[i]) ? highclr : normclr);
  82.     }
  83. }
  84. #pragma check_stack()
  85.  
  86. // CHECK TO SEE IF BOYAN HAS CORRUPTED THE POP-UP MENU (E.G. WITH THE TIMER);
  87. // IF SO, COPY THE CHANGES TO THE SAVE BUFFER AND OPTIONALLY FIX THE MENU:
  88. #pragma check_stack(off)
  89. void
  90. _fastcall UpdateVidSave(
  91.     VIDLINE _based(VidSeg) *line,        // video buffer display line
  92.     BOOL fix                            // fix the menu if TRUE
  93. )
  94. {
  95.     int i;
  96.  
  97.     for (i = 0; i < sizeof(menu); ++i) {    // entire menu line
  98.         if (VidMenu.chat[i].ca != line->chat[i].ca) {    // if corrupted...
  99.             VidSave.chat[i] = line->chat[i];    // save the changes
  100.             if (fix)                    // and if desired...
  101.                 line->chat[i] = VidMenu.chat[i];    // fix the menu
  102.         }
  103.     }
  104. }
  105. #pragma check_stack()
  106.  
  107. //    THIS TRAP ROUTINE INTERCEPTS ALL KEYBOARD BIOS REQUESTS, AND CALLS THE
  108. //    ORIGINAL HANDLER AS APPROPRIATE; ITS PRIMARY PURPOSE IS TO POP-UP THE
  109. //    MENU WHEN <ALT> IS FIRST PRESSED, AND REMOVE IT WHEN EITHER (1) <ALT>
  110. //    IS RELEASED OR (2) ANY REGULAR KEY IS PRESSED:
  111. #if !defined(QCC_)
  112. #pragma intrinsic(_enable)
  113. #endif
  114. #pragma check_stack(off)
  115. void
  116. _interrupt _far KeyReqTrap(
  117.     unsigned _es, unsigned _ds,            // caller's registers
  118.     unsigned _di, unsigned _si,
  119.     unsigned _bp, unsigned _sp,
  120.     unsigned _bx, unsigned _dx,
  121.     unsigned _cx, unsigned _ax,
  122.     unsigned _ip, unsigned _cs,
  123.     unsigned flags )
  124. {
  125.     BYTE opcode;                        // save AH function code here
  126.     static BOOL oldalt, newalt;            // last and current <Alt> key status
  127.     VIDLINE _based(VidSeg) *line;        // last line of video buffer
  128.  
  129.     _enable();                            // allow interrupts
  130.  
  131.     opcode = (BYTE)(_ax >> 8);            // save AH function code
  132.     switch (opcode) {
  133.     case KEYREAD:                        // we only care about these two
  134.     case KEYSTATUS:                        // function codes
  135.         break;
  136.     default:
  137.         _chain_intr(OldKeyReq);            // otherwise go to original handler
  138.     }                                    // for safety (won't return)
  139.  
  140.     _asm    mov        ax,_ax                // ensure AX valid
  141.     OldKeyReq();                        // call original handler (returns)
  142.     _asm    pushf                        // save flags for caller
  143.     _asm    pop        flags
  144.     _asm    mov        _ax,ax                // and save AX for caller
  145.  
  146.     if (0 == VidSeg) {                    // if not initialized yet...
  147.         if (MONOMODE == VIDEOMODE()) {    // pick proper video segment
  148.             VidSeg = MONOBUF;
  149.         }
  150.         else {
  151.             VidSeg = COLORBUF;
  152.         }
  153.         _asm {                            // get video shadow buffer if
  154.             mov        es,VidSeg            // under TopView or DESQview
  155.             xor        di,di
  156.             mov        ah,GETSHADBUF
  157.             int        VIDBIOS
  158.             mov        VidSeg,es
  159.         }
  160.         SetupMenu();                    // initialize menu video buffer
  161.     }
  162.  
  163.     line = 0;                            // point to last line in video
  164.     line += VIDEOROWS();                // display buffer
  165.  
  166.     oldalt = newalt;                    // last <Alt> key state
  167.     newalt = ALTPRESSED();                // current <Alt> key state
  168.  
  169.     // conditions under which menu is NOT displayed:
  170.     if (KEYREAD == opcode || !newalt || (B50SP1 != _sp && B50SP2 != _sp)) {
  171.         if (MenuOn) {                    // if menu popped up...
  172.             UpdateVidSave(line, FALSE);    // save any last changes
  173.             *line = VidSave;            // and remove menu
  174.             MenuOn = FALSE;
  175.         }
  176.     }
  177.     else {                                // otherwise pop-up menu
  178.         if (!MenuOn) {                    // if not yet popped-up...
  179.             if (!oldalt) {                // only pop-up if <Alt> just pressed
  180.                 VidSave = *line;        // save Boyan display
  181.                 *line = VidMenu;        // pop-up menu
  182.                 MenuOn = TRUE;
  183.             }
  184.         }
  185.         else                            // already popped-up
  186.             UpdateVidSave(line, TRUE);    // pick up any changes by Boyan
  187.     }
  188. }
  189. #pragma check_stack()
  190.  
  191. //    MAKE FULL PATH NAME, TAKING THE DRIVE AND DIRECTORY FROM THE 2ND ARGUMENT
  192. //    AND THE FILENAME AND EXTENTION FROM THE 3RD ARGUMENT:
  193. char*                                    // returns path
  194. MakePath(
  195.     char *path,                            // build path here
  196.     const char *drdir,                    // pick up drive and directory
  197.     const char *filext                    // pick up filename and extention
  198. )
  199. {
  200.     char drive[_MAX_DRIVE];                // work areas and pointer
  201.     char dir[_MAX_DIR];
  202.     char fname[_MAX_FNAME];
  203.     char ext[_MAX_EXT];
  204.  
  205.     _splitpath(drdir, drive, dir, NULL, NULL);
  206.     _splitpath(filext, NULL, NULL, fname, ext);
  207.     _makepath(path, drive, dir, fname, ext);
  208.     return path;
  209. }
  210.  
  211. //    GET HELP COLORS FROM BOYAN'S CONFIGURATION FILE (IF IT EXISTS):
  212. void
  213. GetColors(char *path)
  214. {
  215.     int cnf = open(path, O_BINARY | O_RDONLY);
  216.  
  217.     if (-1 == cnf)
  218.         perror(path);
  219.     else {
  220.         lseek(cnf, NORMOFFSET, SEEK_SET);    // Help normal color
  221.         read(cnf, &normclr, sizeof(normclr));
  222.         lseek(cnf, HIGHOFFSET, SEEK_SET);    // Help highlight color
  223.         read(cnf, &highclr, sizeof(highclr));
  224.         close(cnf);
  225.     }
  226. }
  227.  
  228. //    IF MY CONFIGURATION FILE EXISTS, READ MENU TEXT LINE:
  229. void
  230. GetText(char *path)
  231. {
  232.     int cnf = open(path, O_TEXT | O_RDONLY);
  233.  
  234.     if (-1 != cnf) {
  235.         read(cnf, menu, sizeof(menu));
  236.         close(cnf);
  237.     }
  238. }
  239.  
  240. //    RESTORE ORIGINAL KEYBOARD REQUEST BIOS VECTOR:
  241. void
  242. cleanup(void)
  243. {
  244.     if (OldKeyReq)
  245.         _dos_setvect(KEYBIOS, OldKeyReq);
  246. }
  247.  
  248. int
  249. main(int ac, char *av[])
  250. {
  251.     int ret;
  252.  
  253.     MakePath(path, av[0], boyancnf);    // Get colors
  254.     GetColors(path);
  255.     MakePath(path, av[0], b50menucnf);    // Get menu text
  256.     GetText(path);
  257.  
  258.     MakePath(path, av[0], boyancom);    // Boyan's executable pathname
  259.  
  260.     atexit(cleanup);                    // ensure BIOS vector restored
  261.     OldKeyReq = _dos_getvect(KEYBIOS);    // get original key request vector
  262.     _dos_setvect(KEYBIOS, KeyReqTrap);    // install my intercept routine
  263.  
  264.     ret = spawnv(P_WAIT, path, av + 1);    // run Boyan as a child process
  265.     if (-1 == ret)
  266.         perror(path);
  267.  
  268.     return ret;                            // return Boyan's return code
  269. }
  270.  
  271. //    B5MENU.C
  272.